Package org.kc7bfi.jflac.frame

Source Code of org.kc7bfi.jflac.frame.Header

package org.kc7bfi.jflac.frame;

/**
* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001,2002,2003  Josh Coalson
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA  02111-1307, USA.
*/

import java.io.IOException;

import org.kc7bfi.jflac.Constants;
import org.kc7bfi.jflac.io.BitInputStream;
import org.kc7bfi.jflac.metadata.StreamInfo;
import org.kc7bfi.jflac.util.ByteData;
import org.kc7bfi.jflac.util.CRC8;

/**
* Frame header class.
* @author kc7bfi
*/
public class Header {
   
    /** The number of samples per subframe. */
    public int blockSize;
    /** The sample rate in Hz. */
    public int sampleRate;
    /** The number of channels (== number of subframes). */
    public int channels;
    /** The channel assignment for the frame. */
    public int channelAssignment;
    /** The sample resolution. */
    public int bitsPerSample;
   
    /**
     * The frame number or sample number of first sample in frame.
     * use the number_type value to determine which to use.
     */
    public int frameNumber = -1;
   
    /**
     * The sample number for the first sample in the frame.
     */
    public long sampleNumber = -1;
   
    /**
     * CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0).
     * of the raw frame header bytes, meaning everything before the CRC byte
     * including the sync code.
     */
    protected byte crc;
   
    /**
     * The constructor.
     * @param is                    The InputBitStream
     * @param headerWarmup          The header warm-up bytes
     * @param streamInfo            The FLAC Stream Info
     * @throws IOException          Thrown on error reading InputBitStream
     * @throws BadHeaderException   Thrown if header is bad
     */
    public Header(BitInputStream is, byte[] headerWarmup, StreamInfo streamInfo) throws IOException, BadHeaderException {
        int blocksizeHint = 0;
        int sampleRateHint = 0;
        ByteData rawHeader = new ByteData(16); // MAGIC NUMBER based on the maximum frame header size, including CRC
        boolean isKnownVariableBlockSizeStream = (streamInfo != null && streamInfo.getMinBlockSize() != streamInfo.getMaxBlockSize());
        boolean isKnownFixedBlockSizeStream = (streamInfo != null && streamInfo.getMinBlockSize() == streamInfo.getMaxBlockSize());
       
        // init the raw header with the saved bits from synchronization
        rawHeader.append(headerWarmup[0]);
        rawHeader.append(headerWarmup[1]);
       
        // check to make sure that the reserved bits are 0
        if ((rawHeader.getData(1) & 0x03) != 0) { // MAGIC NUMBER
            throw new BadHeaderException("Bad Magic Number: " + (rawHeader.getData(1) & 0xff));
        }
       
        // Note that along the way as we read the header, we look for a sync
        // code inside.  If we find one it would indicate that our original
        // sync was bad since there cannot be a sync code in a valid header.
       
        // read in the raw header as bytes so we can CRC it, and parse it on the way
        for (int i = 0; i < 2; i++) {
            if (is.peekRawUInt(8) == 0xff) { // MAGIC NUMBER for the first 8 frame sync bits
                throw new BadHeaderException("Found sync byte");
            }
            rawHeader.append((byte) is.readRawUInt(8));
        }
       
        int bsType = (rawHeader.getData(2) >> 4) & 0x0f;
        switch (bsType) {
            case 0 :
                if (!isKnownFixedBlockSizeStream)
                    throw new BadHeaderException("Unknown Block Size (0)");
                blockSize = streamInfo.getMinBlockSize();
                break;
            case 1 :
                blockSize = 192;
                break;
            case 2 :
            case 3 :
            case 4 :
            case 5 :
                blockSize = 576 << (bsType - 2);
                break;
            case 6 :
            case 7 :
                blocksizeHint = bsType;
                break;
            case 8 :
            case 9 :
            case 10 :
            case 11 :
            case 12 :
            case 13 :
            case 14 :
            case 15 :
                blockSize = 256 << (bsType - 8);
                break;
            default :
                break;
        }
        //System.out.println("BSType="+bsType+" BS="+blockSize);
       
        int srType = rawHeader.getData(2) & 0x0f;
        switch (srType) {
            case 0 :
                if (streamInfo == null)
                    throw new BadHeaderException("Bad Sample Rate (0)");
                sampleRate = streamInfo.getSampleRate();
                break;
            case 1 :
            case 2 :
            case 3 :
                throw new BadHeaderException("Bad Sample Rate (" + srType + ")");
            case 4 :
                sampleRate = 8000;
                break;
            case 5 :
                sampleRate = 16000;
                break;
            case 6 :
                sampleRate = 22050;
                break;
            case 7 :
                sampleRate = 24000;
                break;
            case 8 :
                sampleRate = 32000;
                break;
            case 9 :
                sampleRate = 44100;
                break;
            case 10 :
                sampleRate = 48000;
                break;
            case 11 :
                sampleRate = 96000;
                break;
            case 12 :
            case 13 :
            case 14 :
                sampleRateHint = srType;
                break;
            case 15 :
                throw new BadHeaderException("Bad Sample Rate (" + srType + ")");
            default :
        }
       
        int asgnType = (int) ((rawHeader.getData(3) >> 4) & 0x0f);
        //System.out.println("AsgnType="+asgnType+" "+(rawHeader.space[3] >> 4));
        if ((asgnType & 8) != 0) {
            channels = 2;
            switch (asgnType & 7) {
                case 0 :
                    channelAssignment = Constants.CHANNEL_ASSIGNMENT_LEFT_SIDE;
                    break;
                case 1 :
                    channelAssignment = Constants.CHANNEL_ASSIGNMENT_RIGHT_SIDE;
                    break;
                case 2 :
                    channelAssignment = Constants.CHANNEL_ASSIGNMENT_MID_SIDE;
                    break;
                default :
                    throw new BadHeaderException("Bad Channel Assignment (" + asgnType + ")");
            }
        } else {
            channels = (int) asgnType + 1;
            channelAssignment = Constants.CHANNEL_ASSIGNMENT_INDEPENDENT;
        }
       
        int bpsType = (int) (rawHeader.getData(3) & 0x0e) >> 1;
        switch (bpsType) {
            case 0 :
                if (streamInfo != null)
                    bitsPerSample = streamInfo.getBitsPerSample();
                else
                    throw new BadHeaderException("Bad BPS (" + bpsType + ")");
                break;
            case 1 :
                bitsPerSample = 8;
                break;
            case 2 :
                bitsPerSample = 12;
                break;
            case 4 :
                bitsPerSample = 16;
                break;
            case 5 :
                bitsPerSample = 20;
                break;
            case 6 :
                bitsPerSample = 24;
                break;
            case 3 :
            case 7 :
                throw new BadHeaderException("Bad BPS (" + bpsType + ")");
            default :
                break;
        }
       
        if ((rawHeader.getData(3) & 0x01) != 0) { // this should be a zero padding bit
            throw new BadHeaderException("this should be a zero padding bit");
        }
       
        if ((blocksizeHint != 0) && isKnownVariableBlockSizeStream) {
            sampleNumber = is.readUTF8Long(rawHeader);
            if (sampleNumber == 0xffffffffffffffffL) { // i.e. non-UTF8 code...
                throw new BadHeaderException("Bad Sample Number");
            }
        } else {
            int lastFrameNumber = is.readUTF8Int(rawHeader);
            if (lastFrameNumber == 0xffffffff) { // i.e. non-UTF8 code...
                throw new BadHeaderException("Bad Last Frame");
            }
            sampleNumber = (long) streamInfo.getMinBlockSize() * (long) lastFrameNumber;
        }
       
        if (blocksizeHint != 0) {
            int blockSizeCode = is.readRawUInt(8);
            rawHeader.append((byte) blockSizeCode);
            if (blocksizeHint == 7) {
                int blockSizeCode2 = is.readRawUInt(8);
                rawHeader.append((byte) blockSizeCode2);
                blockSizeCode = (blockSizeCode << 8) | blockSizeCode2;
            }
            blockSize = blockSizeCode + 1;
        }
       
        if (sampleRateHint != 0) {
            int sampleRateCode = is.readRawUInt(8);
            rawHeader.append((byte) sampleRateCode);
            if (sampleRateHint != 12) {
                int sampleRateCode2 = is.readRawUInt(8);
                rawHeader.append((byte) sampleRateCode2);
                sampleRateCode = (sampleRateCode << 8) | sampleRateCode2;
            }
            if (sampleRateHint == 12)
                sampleRate = sampleRateCode * 1000;
            else if (sampleRateHint == 13)
                sampleRate = sampleRateCode;
            else
                sampleRate = sampleRateCode * 10;
        }
       
        // read the CRC-8 byte
        byte crc8 = (byte) is.readRawUInt(8);
       
        if (CRC8.calc(rawHeader.getData(), rawHeader.getLen()) != crc8) {
            throw new BadHeaderException("STREAM_DECODER_ERROR_STATUS_BAD_HEADER");
        }
    }
   
    /**
     * Return a descriptive string for this object.
     * @return the string description
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return "FrameHeader:"
            + " BlockSize=" + blockSize
            + " SampleRate=" + sampleRate
            + " Channels=" + channels
            + " ChannelAssignment=" + channelAssignment
            + " BPS=" + bitsPerSample
            + " SampleNumber=" + sampleNumber;
    }
}
TOP

Related Classes of org.kc7bfi.jflac.frame.Header

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.